-
Notifications
You must be signed in to change notification settings - Fork 12.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Clang][AST] Fix MS Mangle concept uneval context template instantiation crash #117845
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-clang Author: Max Winkler (MaxEW707) ChangesFixes #115990. MSVC mangling got inadvertently broken here, #83997, when it was fixed what decl context a lambda is apart of for uneval contexts. https://godbolt.org/z/K6jb5v145 for reference. Given the following code snippet
Upon template instantation of I think the longer term more correct solution is to key As a fix for the regression I just created a custom mangling scheme for this case since MSVC has no comparable naming scheme as such a template will never be emitted into the resulting obj as it will never be used. Similarly the following case is also broken for our msvc compat, https://godbolt.org/z/evPo6KTfE, since we do not mangle If anyone has a better alternative to solve this let me know. I couldn't come up with one since the template instantation code path for uneval contexts takes the same code path as any template instantation and thus requires the ability to get back a mangled name for said template instantation. Full diff: https://github.com/llvm/llvm-project/pull/117845.diff 2 Files Affected:
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index dbc161347025c0..c177e3b1d01ddf 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -3374,7 +3374,15 @@ void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T,
void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T,
Qualifiers, SourceRange Range) {
- Error(Range.getBegin(), "template type parameter type") << Range;
+ Out << '?';
+
+ llvm::SmallString<64> Name;
+ Name += "<TTPT_";
+ Name += llvm::utostr(T->getDepth());
+ Name += "_";
+ Name += llvm::utostr(T->getIndex());
+ Name += ">";
+ mangleSourceName(Name);
}
void MicrosoftCXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T,
diff --git a/clang/test/AST/ms-uneval-context-crash.cpp b/clang/test/AST/ms-uneval-context-crash.cpp
new file mode 100644
index 00000000000000..b2f7e58381da81
--- /dev/null
+++ b/clang/test/AST/ms-uneval-context-crash.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -std=c++20 -fms-compatibility -fms-compatibility-version=19.33 -emit-llvm %s -o - -triple=x86_64-windows-msvc | FileCheck %s
+
+template <typename T>
+concept C = requires
+{
+ { T::test([](){}) };
+};
+
+template<typename T>
+struct Widget {};
+
+template <C T>
+struct Widget<T> {};
+
+struct Baz
+{
+ template<typename F>
+ static constexpr decltype(auto) test(F&&) {}
+};
+
+void test()
+{
+ Widget<Baz> w;
+}
+// CHECK: @"?test@@YAXXZ"
|
@@ -0,0 +1,25 @@ | |||
// RUN: %clang_cc1 -std=c++20 -fms-compatibility -fms-compatibility-version=19.33 -emit-llvm %s -o - -triple=x86_64-windows-msvc | FileCheck %s |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think doing codegen (-emit-llvm) in clang/test/AST/ is unusual, those tests normally just look at the AST (though there are exceptions). Maybe there is a better place for this?
{ | ||
Widget<Baz> w; | ||
} | ||
// CHECK: @"?test@@YAXXZ" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose the mangling you're adding doesn't actually show up anywhere since it's only used for a concept? But then why do we need to mangle it in the first place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once we get to CodeGen, the method looks like a regular method, except for the fact that one of the template arguments is a class defined inside a concept instantiation. And CodeGen doesn't have any way to check for "is a template argument a class defined inside a concept". So, like all other methods, we stick it into DeferredDecls. And the key for the DeferredDecls map is the mangled name.
We end up trying to mangle a TemplateTypeParmType because we stick the instantiated class into the scope of an uninstantiated class template.
So no, we don't actually need to mangle it, but there's currently no way for CodeGen to check for this situation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fix LGTM. I do wonder if the test should live in CodeGen/ instead, but I don't have a strong feeling about this (AST/ already seems to have some codegen tests).
Moving the test would be more consistent indeed |
Fixes #115990.
MSVC mangling got inadvertently broken here, #83997, when it was fixed what decl context a lambda is apart of for uneval contexts.
https://godbolt.org/z/K6jb5v145 for reference.
Given the following code snippet
Baz::test
has a deduced return type which means we must instantiate that template even in an unevaluated context.The lambda inside the concept is within the decl context of
struct Widget<T> {};
. So we end up needing to mangle a name ofBaz::test<Widget<template-type-0-0>::lambda()>>()
since the lambda isn't apart of an instantiated substituted classWidget
yet at the point the lambda is instantiated.Upon template instantation of
test
we end up asking for the mangled name so we can add this instantiation toCodeGenModule::DefferredDecls
sincetest
is now referenced but not yet used.I think the longer term more correct solution is to key
DefferedDecls
off of something else than the mangled name to avoid having to mangle names for instantations that are referenced but will never be used since they are only instantiated from an unevaluated context.As a fix for the regression I just created a custom mangling scheme for this case since MSVC has no comparable naming scheme as such a template will never be emitted into the resulting obj as it will never be used.
Similarly the following case is also broken for our msvc compat, https://godbolt.org/z/evPo6KTfE, since we do not mangle
decltype(Expr)
. The Itanium ABI gets away with this as the entiredecltype(Expr)
expression must be mangled as is for that ABI.The MSVC ABI never mangles a decltype. Only the final canonical deduced type is mangled into the name so we never need to worry about manglingdecltype
except in the uneval context edge case.I want to hold off fixing this case until I can see if I can come up with a better more holistic solution around
DefferedDecls
first. I'll get a github tracking issue created for it however.If anyone has a better alternative to solve this let me know. I couldn't come up with one since the template instantation code path for uneval contexts takes the same code path as any template instantation and thus requires the ability to get back a mangled name for said template instantation.